/*
 * Multiples redacteurs et un lecteur. 
 * Priorité aux redacteurs.
 */

#define _MULTI_THREADED
#include "lect-redac_moniteur.h"
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#define MAX_LECT 2
#define NUM_REPET 2

int nblect_attente = 0;
int nblect = 0; //readers executing
int nbredac_attente = 0;
int nbredac = 0; //writers executing 
pthread_cond_t lecteurs = PTHREAD_COND_INITIALIZER;
pthread_cond_t redacteurs = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex_lr = PTHREAD_MUTEX_INITIALIZER;

/*
int main()
{
	pthread_t thd_redac[MAX_LECT];
	pthread_t thd_lect[MAX_LECT];
	int rc;
	
	//redacteur thread
	for(int i = 0; i < MAX_LECT; i++){
		rc = pthread_create(&thd_redac[i], NULL, redac, (void *)i);
		if(rc){
			perror("erreur thd redac");
			exit(-1);
		}
	}
	
	//lecteur threads
	for(int i = 0; i < MAX_LECT; i++){
		rc = pthread_create(&thd_lect[i], NULL, lect, (void *)i);
		if(rc){
			perror("erreur thd lect");
			exit(-1);
		}
	}
	pthread_mutex_destroy(&mutex_lr);
	pthread_exit(NULL);
}
*/

void debut_lire(int id)
{
	pthread_mutex_lock(&mutex_lr);
		printf("debut_lire %d\n", id);
 		nblect_attente++;
		while(nbredac > 0 || nbredac_attente > 0){
			printf("lecteur %d va attendre\n", id);
			pthread_cond_wait(&lecteurs, &mutex_lr);
			printf("lecteur %d est reveille\n", id);
			pthread_cond_broadcast(&lecteurs);
		}
		nblect_attente --;
		nblect++;
	pthread_mutex_unlock(&mutex_lr);
}

void fin_lire(int id)
{
	pthread_mutex_lock(&mutex_lr);
		printf("fin_lire %d\n", id);
		nblect--;
		if(nblect == 0){
			printf("lecteur %d va reveiller les redacteurs\n", id);
			pthread_cond_broadcast(&redacteurs);
		}
	pthread_mutex_unlock(&mutex_lr);
}

void debut_ecrire(int id)
{
	pthread_mutex_lock(&mutex_lr);
		printf("debut ecrire %d\n", id);
		nbredac_attente++;
		while(nblect > 0 || nbredac > 0){
			printf("redacteur %d va attendre\n", id);
			pthread_cond_wait(&redacteurs, &mutex_lr);
			printf("redacteur %d est reveille\n", id);
		}
		nbredac = 1;
		nbredac_attente--;
	pthread_mutex_unlock(&mutex_lr);
}

void fin_ecrire(int id)
{
	pthread_mutex_lock(&mutex_lr);
		printf("fin ecrire %d\n", id);
		nbredac = 0; 
		if(nbredac_attente > 0){
			printf("redacteur %d va reveiller les autres redacteurs en attendre\n", id);
			pthread_cond_broadcast(&redacteurs);
		}
		else{
			printf("redacteur %d va reveiller les lecteurs en attendre\n", id);
			pthread_cond_broadcast(&lecteurs);
		}
	pthread_mutex_unlock(&mutex_lr);
}
void *redac(void *num_redac)
{
	int id = (int)num_redac;
	for(int i = 0; i < NUM_REPET; i++){
		printf("redacteur %d va executer 'debut_ecrire()'\n", id);
		debut_ecrire(id);
		printf("redacteur %d va executer 'fin_ecrire()'\n", id);
		fin_ecrire(id);
	}
	
	return NULL;
		
}

void *lect(void *num_lect)
{
	int id = (int)num_lect;
	for(int i = 0; i < NUM_REPET; i++){
		printf("lecteur %d va executer 'debut_lire()'\n", id); 
		debut_lire(id);
		printf("lecteur %d va executer 'fin_lire()'\n", id);
		fin_lire(id);
	}
	
	return NULL;
}


